import 'package:agora_rtm/src/impl/gen/rtm_result_handler.dart';
import 'package:agora_rtm/src/impl/extensions.dart';
import 'package:agora_rtm/src/binding_forward_export.dart';
import 'package:agora_rtm/src/bindings/gen/agora_rtm_presence_impl.dart'
    as native_binding;
import 'package:flutter/services.dart';

import 'agora_rtm_client_ohos_impl.dart';

class StateItem {
  String key;
  String value;
  StateItem(this.key,this.value);
  Map<String, dynamic> toMap() {
    return {
      'key': key,
      'value': value,
    };
  }
}

class RtmPresenceOhosImpl implements RtmPresence {
  RtmPresenceOhosImpl(this._methodChannel,this.rtmResultHandler);

  final MethodChannel _methodChannel;
  final RtmResultHandler rtmResultHandler;

  @override
  Future<(RtmStatus, GetOnlineUsersResult?)> getOnlineUsers(String channelName, RtmChannelType channelType, {bool includeUserId = true, bool includeState = false, String? page}) async {
    final Map<String, dynamic> options = {
      "includeUserId":channelName,
      "includeState":includeState,
      "page":page,
    };
    final Map<String, dynamic> args = {
      "channelName":channelName,
      "channelType":channelType.value(),
      "options":jsonEncode(options),
    };
    var code = await _methodChannel.invokeMethod("getOnlineUsers", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (GetOnlineUsersResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, GetStateResult?)> getState(String channelName, RtmChannelType channelType, String userId) async {
    final Map<String, dynamic> args = {
      "channelName":channelName,
      "channelType":channelType.value(),
      "userId":userId,
    };
    var code = await _methodChannel.invokeMethod("getState", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (GetStateResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, GetUserChannelsResult?)> getUserChannels(String userId) async {
    final Map<String, dynamic> args = {
      "channelName":userId,
    };
    var code = await _methodChannel.invokeMethod("getState", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (GetUserChannelsResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, RemoveStateResult?)> removeState(String channelName, RtmChannelType channelType, {List<String> states = const []}) async {
    final Map<String, dynamic> args = {
      "channelName":channelName,
      "channelType":channelType.value(),
      "stateKeys":states,
    };
    var code = await _methodChannel.invokeMethod("getState", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (RemoveStateResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, SetStateResult?)> setState(String channelName, RtmChannelType channelType, Map<String, String> state) async {
    List<StateItem> stateItems = [];
    state.forEach((k,v){
      stateItems.add(StateItem(k, v));
    });
    final Map<String, dynamic> args = {
      "channelName":channelName,
      "channelType":channelType.value(),
      "stateItems":stateItems.map((a)=>a.toMap()).toList(),
    };
    var code = await _methodChannel.invokeMethod("setState", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (SetStateResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, WhereNowResult?)> whereNow(String userId) async {
    final Map<String, dynamic> args = {
      "channelName":userId,
    };
    var code = await _methodChannel.invokeMethod("whereNow", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (WhereNowResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }

  @override
  Future<(RtmStatus, WhoNowResult?)> whoNow(String channelName, RtmChannelType channelType, {bool includeUserId = true, bool includeState = false, String page = ''}) async {
    final Map<String, dynamic> options = {
      "includeUserId":includeUserId,
      "includeState":includeState,
      "page":page,
    };
    final Map<String, dynamic> args = {
      "channelName":channelName,
      "channelType":channelType.value(),
      "options":jsonEncode(options)
    };
    var code = await _methodChannel.invokeMethod("whoNow", args);
    Map<String,dynamic> map = jsonDecode(code!);
    final (WhoNowResult result, RtmErrorCode errorCode) = await rtmResultHandler.request(int.parse(map['requestId']));
    return (RtmClientOhosImpl.getRtmStatus(map['errorCode']),result);
  }
}
